package ru.fadeev.crammer.ui.window;

import java.awt.*;
import java.awt.event.*;
import java.util.Locale;
import java.util.Vector;

import javax.swing.*;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.TableCellEditor;
import javax.swing.table.TableModel;

import ru.fadeev.crammer.GFIndicesStorage;
import ru.fadeev.crammer.Settings;
import ru.fadeev.crammer.Utils;
import ru.fadeev.crammer.data.Dictionary;
import ru.fadeev.crammer.data.Sheet;
import ru.fadeev.crammer.data.WordRecord;
import ru.fadeev.crammer.data.WordEditList;
import ru.fadeev.crammer.data.WordEditListRecord;
import ru.fadeev.crammer.ui.ArrowOptionPane;
import ru.fadeev.crammer.ui.CrammerToolbarButton;
import ru.fadeev.crammer.ui.LimitedPlainDocument;
import ru.fadeev.crammer.ui.TableTextFieldFactory;
import ru.fadeev.crammer.ui.TransTextField;


/**
 * AddEditSheetDialog provides GUI for adding or editing Sheet and Words in it.
 * Information about all changes that user makes with words are stored 
 * in editList. And if then user presses OK button these changes are saved,
 * otherwise sheet's left intact.
 * @author Konstantin Fadeyev
 *
 */
public class AddEditSheetDialog extends JDialog {
	// Constants
	public final static int ADD_MODE = 0;
	public final static int EDIT_MODE = 1;
	
	public final static int BTN_OK = 100;
	public final static int BTN_CANCEL = 101;
	
    private static Color SELECTION_COLOR = new Color(220,220,255);;

	// UI Components
	private JPanel mainPanel;
	private JPanel topPanel;
	private JPanel mainPanelWithoutTop;
	private JPanel toolBarsPanel;
	private JLabel sheetNameLabel;
	private JTextField sheetNameTextField;
	
	private JToolBar wordsToolBar;
    private JButton addWordRecordButton;
    private JButton deleteWordRecordButton;
    private JButton moveUpWordRecordButton;
    private JButton moveDownWordRecordButton;
    private JButton showTransPromptButton;

	private JToolBar bankToolBar;
    private JButton checkBankWordButton;
    private JButton checkBankAllWordsButton;

	private JScrollPane wordsScrollPane;
	private JTable wordsTable;
    private EditSheetTableCellRenderer wordsTableCellRenderer;
    private EditSheetTableModel wordsTableModel;
    
	private JPanel bottomPanel;
	private JPanel okCancelButtonsPanel;
    private JButton okButton;
    private JButton cancelButton;
    
    private JWindow promptWindow;
    private Point windowLocation;

    // User fields
    private Dictionary dictionary;
    private int dictionaryIndex;
    private WordEditList editList;
    
    /**
     * Dialog mode (add or edit sheet)
     */
    private int mode;
    private int pressedButton;	
    private int sheetIndex;
    private GFIndicesStorage storage;
    
    
    /**
     * Initializes dialog for adding sheet
     * @param owner parent window
     * @param dictionary dictionary to add sheet in
     * @param storage object of GFIndicesStorage class
     * @param dictionaryIndex index of dictionary to add sheet in
     */
    public AddEditSheetDialog(JFrame owner, Dictionary dictionary, 
    		GFIndicesStorage storage, int dictionaryIndex) {
    	this(owner);
    	this.dictionary = dictionary;
    	this.storage = storage;
    	this.dictionaryIndex = dictionaryIndex;
    	editList = new WordEditList();  
    	
        mode = ADD_MODE;
        setTitle("Adding sheet");      
       
        initComponents();
        placeComponents();
        refreshWordsButtons();
    }
    
    
    /**
     * Initializes dialog for editing sheet
     * @param owner parent window
     * @param dictionary dictionary to edit sheet in
     * @param sheetIndex sheet index to edit
     * @param storage object of GFIndicesStorage class
     * @param dictionaryIndex index of dictionary to edit sheet in
     */
    public AddEditSheetDialog(JFrame owner, Dictionary dictionary, 
    		int sheetIndex, GFIndicesStorage storage, int dictionaryIndex) {
    	this(owner);
               
    	this.dictionary = dictionary;  
    	this.sheetIndex = sheetIndex;
    	this.dictionaryIndex = dictionaryIndex;
    	this.storage = storage;   	
    	Sheet sheet = dictionary.getSheet(sheetIndex);
        editList = new WordEditList(sheet);    
        
        mode = EDIT_MODE;
        setTitle("Editing sheet");   
        
        initComponents();
        placeComponents();
        refreshWordsButtons();
    }
    
    
    /**
     * Constructs and initializes AddEditSheetDialog.
     * @param owner parent window
     */
    private AddEditSheetDialog(JFrame owner) {
    	super(owner,true);
    	 
    	int x = Settings.getInt("addEditSheetDialogX");
     	int y = Settings.getInt("addEditSheetDialogY");
     	int w = Settings.getInt("addEditSheetDialogW");
     	int h = Settings.getInt("addEditSheetDialogH");	
     	
        if(x<0 || y<0 || w<0 || h<0) {
        	Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
            setSize(screenSize.width * 9/10, screenSize.height* 8/10);
            setLocation(screenSize.width/20, screenSize.height/20);
        } else {
        	setSize(w, h);
        	setLocation(x, y);        	
        }
               
        pressedButton = BTN_CANCEL;        
    }

    
    /**
     * After dialog is closed, call this function to find out which option
     * user picked (OK or Cancel)
     * @return pressed button (one of BTN_OK, BTN_CANCEL)
     */
    public int getPressedButton() {
    	return pressedButton;
    }
    
    /**
     * Overwritten, so it saves window location when dialog is closed
     */
    public void setVisible(boolean v) {
    	if(v == false) {
	    	Settings.setInt("addEditSheetDialogX", getX());
	    	Settings.setInt("addEditSheetDialogY", getY());
	    	Settings.setInt("addEditSheetDialogW", getWidth());
	    	Settings.setInt("addEditSheetDialogH", getHeight());
	    	Settings.setInt("addEditPromptWindowX", promptWindow.getX());
	    	Settings.setInt("addEditPromptWindowY", promptWindow.getY());
	    	Settings.setBoolean("showPromptWindow", promptWindow.isVisible());
    	}
    	windowLocation = getLocation();
    	super.setVisible(v);
    }
    
    
    /**
     * Cancel button action handler. Closes dialog.
     */
    private void cancelButtonAction() {
        pressedButton = BTN_CANCEL;
        setVisible(false);
    }

    
    /**
     * Deletes selected words from sheet. Actually words are not deleted, rather
     * information about their deletion goes to editList, and if user presses 
     * cancel button, sheet remains intact.
     */
    private void deleteWordRecords() {
    	Utils.finishTableEditing(wordsTable);
    	
		int n = ArrowOptionPane.showConfirmDialog(this, 
				"Selected words will be deleted.\n" +
                "Are you sure?","Are you sure?", 
                JOptionPane.YES_NO_OPTION);
	    switch(n) {
        case JOptionPane.OK_OPTION:
        	
        	int[] indices = wordsTable.getSelectedRows();
        	int columnIndex = wordsTable.getSelectedColumn();
        	       	
        	 // if last row (there is no words for) selected 
        	 // then this row should not be processed
        	if(indices[indices.length - 1] == editList.nonDeleteSize()) {
        		indices = new int[wordsTable.getSelectedRows().length-1]; 
        		System.arraycopy(wordsTable.getSelectedRows(), 0, indices, 0, 
        												indices.length); 
        	}
        	int indexToSelect = indices[indices.length-1] - indices.length + 1;
        	
        	editList.deleteRecords(indices);
        	wordsTableModel.fireTableDataChanged();
			if( (indexToSelect == editList.nonDeleteSize()) && (indexToSelect != 0) ) {
				indexToSelect = indexToSelect - 1;
			}
			if(indexToSelect >= 0) {
				wordsTable.setRowSelectionInterval(indexToSelect, indexToSelect);
			}
			if(columnIndex >= 0) {
				wordsTable.setColumnSelectionInterval(columnIndex, columnIndex);
			}
			wordsTable.requestFocus();
			
            break;
        default:      
            return;
	    }    	
    }
    
    
    /**
     * Initializes UI Components of dialog
     */
    private void initComponents() {
    	// Main panel and sheet name text field 
        mainPanel = new JPanel();
        topPanel = new JPanel(); 
        mainPanelWithoutTop = new JPanel();
        toolBarsPanel = new JPanel(); 
        sheetNameLabel = new JLabel("Sheet name:"); 
        sheetNameTextField = new JTextField();
    	LimitedPlainDocument sheetNameDocument = 
			new LimitedPlainDocument(Settings.SHEET_NAME_MAX_LENGTH);
    	sheetNameTextField.setDocument(sheetNameDocument);
 	
        if(mode == EDIT_MODE) {
        	Sheet sheet = dictionary.getSheet(sheetIndex);
        	sheetNameTextField.setText(sheet.getName());
        }
        
        // Words buttons
		ImageIcon addWordIcon = new ImageIcon("icons/16/add.png");
		addWordRecordButton = new CrammerToolbarButton(addWordIcon, 
				"Insert New Word");
		addWordRecordButton.addActionListener(
			    new AbstractAction() {
			        public void actionPerformed(ActionEvent ev) {
			        	insertWordRecord();
			        }
			    });

		ImageIcon deleteWordIcon = new ImageIcon("icons/16/delete.png");
        deleteWordRecordButton = new CrammerToolbarButton(deleteWordIcon, 
        		"Delete Words");        
        deleteWordRecordButton.addActionListener(
			    new AbstractAction() {
			        public void actionPerformed(ActionEvent ev) {
			        	deleteWordRecords();
			        }
			    });

		ImageIcon moveUpWordIcon = new ImageIcon("icons/16/up.png");
		moveUpWordRecordButton = new CrammerToolbarButton(moveUpWordIcon, 
				"Move Word Up");		
		moveUpWordRecordButton.addActionListener(
			    new AbstractAction() {
			        public void actionPerformed(ActionEvent ev) {
			        	moveUpWordRecords();
			        }
			    });
		
		ImageIcon moveDownWordIcon = new ImageIcon("icons/16/down.png", "Move Word Down");
		moveDownWordRecordButton = new CrammerToolbarButton(moveDownWordIcon, 
				"Move Word Down");     
		moveDownWordRecordButton.addActionListener(
			    new AbstractAction() {
			        public void actionPerformed(ActionEvent ev) {
			        	moveDownWordRecords();
			        }
			    });

		ImageIcon showTransPromptIcon = new ImageIcon("icons/16/showTransMap.png");
		showTransPromptButton = new CrammerToolbarButton(showTransPromptIcon, 
				"Show Transcription Prompt");     
		showTransPromptButton.addActionListener(
			    new AbstractAction() {
			        public void actionPerformed(ActionEvent ev) {
			        	promptWindow.setVisible(!promptWindow.isVisible());
			        }
			    });
		
		// Words toolbar
		wordsToolBar = new JToolBar(JToolBar.HORIZONTAL);
		wordsToolBar.setFloatable(false);
        
		wordsToolBar.add(addWordRecordButton);
		wordsToolBar.add(deleteWordRecordButton);
		wordsToolBar.addSeparator();
		wordsToolBar.add(moveUpWordRecordButton);
		wordsToolBar.add(moveDownWordRecordButton);
		wordsToolBar.addSeparator();
		wordsToolBar.add(showTransPromptButton);
		
		// Phrases Bank toolbar and buttons
		ImageIcon checkBankWordIcon = 
			new ImageIcon("icons/16/checkBankWord.png");
		checkBankWordButton = new CrammerToolbarButton(checkBankWordIcon,
				"Look up in Phrases Bank for selected word");
		checkBankWordButton.addActionListener(
			    new AbstractAction() {
			        public void actionPerformed(ActionEvent ev) {
			        	int[] indices = wordsTable.getSelectedRows();
			        	
			        	int notFakeLength = indices.length;
			        	
			    		// if fake row is selected
			    		if(indices[indices.length - 1] == 
			    				editList.nonDeleteSize()) {
			    			notFakeLength = notFakeLength - 1;
			    		}
			        	Sheet sheet = dictionary.getSheet(sheetIndex);
			        	Vector<String> wordVector = new Vector<String>();
			    		
			        	for(int i = 0; i < notFakeLength; i++) {
			        		WordEditListRecord editListRecord = 
			        			editList.getNonDeleteRecord(indices[i]);
			        		if(editListRecord.status == WordEditListRecord.NO_CHANGE || 
			            			editListRecord.status == WordEditListRecord.UPDATED) {			        			
					        	WordRecord wordRecord = 
					        		sheet.getWordRecord(editListRecord.getIndex());
					        	if(!wordRecord.getWord().trim().equals("")) {
				        			wordVector.addElement(wordRecord.getWord());
				        		}
			            	}
			        	}
			        	if(wordVector.size() > 0) {
			        		storage.addPHBTask(wordVector);
			        	}
			        }
			    });

		ImageIcon checkBankAllWordsIcon = new ImageIcon("icons/16/checkBankWords.png");
		checkBankAllWordsButton = new CrammerToolbarButton(checkBankAllWordsIcon, 
				"Look up in Phrases Bank for all words in sheet");        
		checkBankAllWordsButton.addActionListener(
			    new AbstractAction() {
			        public void actionPerformed(ActionEvent ev) {
			        	Sheet sheet = dictionary.getSheet(sheetIndex);
			        	Vector<String> wordVector = new Vector<String>();
			        	for(int i = 0; i < editList.nonDeleteSize(); i++) {
			        		WordEditListRecord editListRecord = 
			        			editList.getNonDeleteRecord(i);
			        		if(editListRecord.status == WordEditListRecord.NO_CHANGE || 
			            			editListRecord.status == WordEditListRecord.UPDATED) {			        			
					        	WordRecord wordRecord = 
					        		sheet.getWordRecord(editListRecord.getIndex());
					        	if(!wordRecord.getWord().trim().equals("")) {
				        			wordVector.addElement(wordRecord.getWord());
				        		}
			            	}
			        	}
			        	if(wordVector.size() > 0) {
			        		storage.addPHBTask(wordVector);
			        	}
			        }
			    });

        bankToolBar = new JToolBar(JToolBar.HORIZONTAL);
        bankToolBar.setFloatable(false);
        
        bankToolBar.add(checkBankWordButton);
        bankToolBar.add(checkBankAllWordsButton);
        
        // Words table
        wordsTableModel = new EditSheetTableModel(editList);       
        wordsTable = new JTable(wordsTableModel);
        wordsTable.putClientProperty("JTable.autoStartsEdit", Boolean.FALSE);
        wordsTable.putClientProperty("terminateEditOnFocusLost", Boolean.TRUE);
        
        AddEditSelectionListener wordsTableListener 
        		= new AddEditSelectionListener(wordsTable, this);
        wordsTable.getSelectionModel()
        		.addListSelectionListener(wordsTableListener);
        wordsTable.getColumnModel().getSelectionModel()
            	.addListSelectionListener(wordsTableListener);
        
        wordsTableCellRenderer = new EditSheetTableCellRenderer();
        wordsTable.setDefaultRenderer(String.class, wordsTableCellRenderer);

        EditSheetCellEditor testEditor 
        		= new EditSheetCellEditor(wordsTable);      
        wordsTable.setDefaultEditor(String.class, testEditor);
        wordsTable.setCellEditor(testEditor);
        
        wordsTable.getColumnModel().getColumn(0).setPreferredWidth(110);
        wordsTable.getColumnModel().getColumn(1).setPreferredWidth(110);
        wordsTable.getColumnModel().getColumn(2).setPreferredWidth(220);
        wordsTable.getColumnModel().getColumn(3).setPreferredWidth(500);
        
        wordsTable.addFocusListener(
	        new FocusAdapter() {
	        	public void focusGained(FocusEvent fe) {
	        		if( (wordsTable.getSelectedRow() < 0 ) &&
	        				(wordsTable.getSelectedColumn() < 0) &&
	        				wordsTable.getRowCount() > 0) {
	        			wordsTable.setRowSelectionInterval(0, 0);	
	        			wordsTable.setColumnSelectionInterval(0, 0);	
	        		}
	        	}
	        });

        wordsScrollPane = new JScrollPane(wordsTable);
        
        // OK, Cancel buttons
        okButton = new JButton("OK");
        getRootPane().setDefaultButton(okButton);
        
		cancelButton = new JButton("Cancel");
        bottomPanel = new JPanel();   
        okCancelButtonsPanel = new JPanel();        
        
        okButton.addActionListener(
			    new AbstractAction() {
			        public void actionPerformed(ActionEvent ev) {
			        	okButtonAction();
			        }
			    });
        
        cancelButton.addActionListener(
			    new AbstractAction() {
			        public void actionPerformed(ActionEvent ev) {
			           	cancelButtonAction();
			        }
		        });
        
        setContentPane(mainPanel);
        
        initTransPrompt();
        addComponentListener(   		
        		new ComponentAdapter() {       			
        			public void componentMoved(ComponentEvent e) {
        				Point newLoc = getLocation();
       					int newPromptX = promptWindow.getX() + newLoc.x 
       							- windowLocation.x;
       					int newPromptY = promptWindow.getY() + newLoc.y 
       							- windowLocation.y;
       					promptWindow.setLocation(newPromptX, newPromptY);
        		    	windowLocation = newLoc;
        		    }
        		});
    }
    
    
    /**
     * Initializes TranscriptionPromptWindow (map that matches transcription 
     * symbols and keyboard keys)
     */
    private void initTransPrompt() {
    	promptWindow = new TranscriptionPromptWindow(this);
    	
    	int x = Settings.getInt("addEditPromptWindowX");
     	int y = Settings.getInt("addEditPromptWindowY");
     	if(x < 0 || y < 0) {
     		promptWindow.setLocation(getX() + 250, getY() + 10);
     	} else {
     		promptWindow.setLocation(x, y);
     	}
     	promptWindow.setVisible(Settings.getBoolean("showPromptWindow"));
    }
        

    /**
     * Inserts new empty word record in the list  
     */
    private void insertWordRecord() {
    	Utils.finishTableEditing(wordsTable);
    	
    	int rowIndex = wordsTable.getSelectedRow();
    	int columnIndex = wordsTable.getSelectedColumn();
		if(rowIndex < 0) {
			rowIndex = editList.nonDeleteSize();
		}
		if(columnIndex < 0) {
			columnIndex = 0;
		}

		editList.insertRecord("", "", "", "", rowIndex);
		wordsTableModel.fireTableDataChanged();
		wordsTable.setRowSelectionInterval(rowIndex, rowIndex);
		wordsTable.setColumnSelectionInterval(columnIndex, columnIndex);
		wordsTable.requestFocus();
    }

    
    /**
     * Moves selected words a one row down
     */
    private void moveDownWordRecords() {
    	Utils.finishTableEditing(wordsTable);
    	
    	int[] indices = wordsTable.getSelectedRows();
    	int[] newIndices = new int[indices.length]; 
    	int columnIndex = wordsTable.getSelectedColumn();
    	
    	for(int i = indices.length - 1; i >= 0 ; i--) {
    		
    		// if not fake row
    		if(indices[i] != editList.nonDeleteSize()) {
    			editList.swapRecords(indices[i], indices[i] + 1);
        		newIndices[i] = indices[i] + 1;
    		} else {
    			newIndices[i] = indices[i];
    		}
    	}
    	
    	wordsTableModel.fireTableDataChanged();
    	for(int i = 0; i < newIndices.length; i++) {
    		wordsTable.addRowSelectionInterval(newIndices[i], newIndices[i]);
    	}
		if(columnIndex >= 0) {
			wordsTable.setColumnSelectionInterval(columnIndex, columnIndex);
		}
    	
    	wordsTable.requestFocus();
    }
    
    
    /**
     * Moves selected words a one row up
     */
    private void moveUpWordRecords() {
    	Utils.finishTableEditing(wordsTable);
    	
    	int[] indices = wordsTable.getSelectedRows();
    	int[] newIndices = new int[indices.length]; 
    	int columnIndex = wordsTable.getSelectedColumn();
    	
    	for(int i = 0; i < indices.length; i++)	{
    		
    		// if not fake row
    		if(indices[i] != editList.nonDeleteSize()) {
    			editList.swapRecords(indices[i]-1, indices[i]);
        		newIndices[i] = indices[i] - 1;
    		} else {
    			newIndices[i] = indices[i];
    		}
    	}
    	
    	wordsTableModel.fireTableDataChanged();
    	for(int i = 0; i < newIndices.length; i++) {
    		wordsTable.addRowSelectionInterval(newIndices[i], newIndices[i]);
    	}
		if(columnIndex >= 0) {
			wordsTable.setColumnSelectionInterval(columnIndex, columnIndex);
		}
    	
    	wordsTable.requestFocus();
    }
    
    
    /**
     * Ok button action handler. Validates entered values and if all ok saves words
     * to database.
     */
    private void okButtonAction() {
    	Utils.finishTableEditing(wordsTable);  		
    	if(sheetNameTextField.getText().trim().equals("")) {
    		JOptionPane.showMessageDialog(this, "Enter sheet name to continue.",
    				"Warning", JOptionPane.WARNING_MESSAGE);
    		sheetNameTextField.requestFocus();
    		return;
    	}
    	int [] blankLineIndices = new int[editList.nonDeleteSize()];
    	int blankLineCount = 0;
    	for(int i = 0; i < editList.nonDeleteSize(); i++) {
    		 WordEditListRecord record = editList.getNonDeleteRecord(i);
    		 WordRecord wordRecord = record.getWordRecord();
    		if(wordRecord.getWord().equals("")) {
    			blankLineIndices[blankLineCount] = i;
    			blankLineCount++;
    		}
    	}
    	int [] blankLineIndicesTemp = new int[blankLineCount];
    	System.arraycopy(blankLineIndices, 0, blankLineIndicesTemp, 
    			0, blankLineCount);
    	
    	editList.deleteRecords(blankLineIndicesTemp);
    	
    	Sheet sheet;
    	if(mode == ADD_MODE) {
    		sheet = new Sheet();
    		sheet.setName(sheetNameTextField.getText().trim());
    		dictionary.addSheet(sheet, storage);
    	} else {
    		sheet = dictionary.getSheet(sheetIndex);
    		sheet.setName(sheetNameTextField.getText().trim());
    		dictionary.updateSheet(sheetIndex);    		
    	}
    	sheet.saveWordRecords(editList, storage, dictionaryIndex, sheetIndex);
    	
    	pressedButton = BTN_OK;
    	setVisible(false);
    }
    
    
    /**
     * Places UI components using different layout managers
     */
    private void placeComponents() {
    	mainPanel.setLayout(new BorderLayout());   	
    	mainPanel.add(topPanel, BorderLayout.NORTH);
    	mainPanel.add(mainPanelWithoutTop, BorderLayout.CENTER);
    	
    	topPanel.setPreferredSize(new Dimension(30,34));
    	topPanel.setLayout(null);
    	topPanel.add(sheetNameLabel);
    	topPanel.add(sheetNameTextField);
    	
    	sheetNameLabel.setBounds(10, 5, 70, 20);	
    	sheetNameTextField.setBounds(80, 5, 400, 20);
    	
    	mainPanelWithoutTop.setLayout(new BorderLayout());
    	mainPanelWithoutTop.add(toolBarsPanel, BorderLayout.NORTH);
    	mainPanelWithoutTop.add(wordsScrollPane, BorderLayout.CENTER);
    	mainPanelWithoutTop.add(bottomPanel, BorderLayout.SOUTH);
    	
    	toolBarsPanel.setLayout(new BorderLayout());
    	toolBarsPanel.add(wordsToolBar, BorderLayout.WEST);
    	toolBarsPanel.add(bankToolBar, BorderLayout.EAST);
    	
    	bottomPanel.setPreferredSize(new Dimension(200, 40));
    	bottomPanel.setLayout(new BorderLayout());
    	bottomPanel.add(okCancelButtonsPanel, BorderLayout.EAST); 	
    	
    	okCancelButtonsPanel.setPreferredSize(new Dimension(210, 40));
    	okCancelButtonsPanel.setLayout(null);
    	okCancelButtonsPanel.add(okButton);
    	okCancelButtonsPanel.add(cancelButton);
    	
    	okButton.setBounds(10, 10, 90, 20);
    	cancelButton.setBounds(110, 10, 90, 20);   	
    }
    
    
    /**
     * Enable/disable toolbars buttons depending on selected words.
     */
    private void refreshWordsButtons() {
    	boolean deleteEnable = true;
    	boolean moveUpEnable = true;
    	boolean moveDownEnable = true;
    	boolean checkBankEnable = true;
    	
    	int[] indices = wordsTable.getSelectedRows();
    	
    	// if no rows selected or only one fake row is selected 
    	// (fake row is last row that doesn't match word data,
    	// user can add new word by starting editing fake row)
    	if((indices.length == 0)
    			|| ((indices.length == 1) 
    					&& (indices[0] == editList.nonDeleteSize()))) {
    		deleteEnable = false;
        	moveUpEnable = false;
        	moveDownEnable = false;
        	checkBankEnable = false;
    	} else {
        	// if first row selected
        	if(indices[0] == 0)
        		moveUpEnable = false;
        	
        	int notFakeLength = indices.length;
        	
    		// if fake row is selected
    		if(indices[indices.length - 1] == editList.nonDeleteSize()) {
    			notFakeLength = notFakeLength - 1;
    		}
    		
    		// if last not fake selected row is last in the sheet
			if(indices[notFakeLength - 1] == editList.nonDeleteSize() - 1)
				moveDownEnable = false;
    		
    		// if among selected words there is at least one that is not just
    		// inserted
        	boolean onlyInsertedWords = true;
        	for(int i = 0; i < notFakeLength; i++) {
        		WordEditListRecord editListRecord = 
        			editList.getNonDeleteRecord(indices[i]);
        		if(editListRecord.status == WordEditListRecord.NO_CHANGE || 
            			editListRecord.status == WordEditListRecord.UPDATED) {
        			onlyInsertedWords = false;
            	}
        	}
        	if(onlyInsertedWords)
        		checkBankEnable = false;
    	}

    	deleteWordRecordButton.setEnabled(deleteEnable);
    	checkBankWordButton.setEnabled(checkBankEnable && (mode != ADD_MODE));
    	moveUpWordRecordButton.setEnabled(moveUpEnable);
    	moveDownWordRecordButton.setEnabled(moveDownEnable );
    	checkBankAllWordsButton.setEnabled(mode != ADD_MODE); 
    }
    
    
    /**
     * AddEditSelectionListener class represents selection listener 
     * for words table in AddEditSheetDialog
     * @author Konstantin Fadeyev
     *
     */
    private class AddEditSelectionListener implements ListSelectionListener {
    	JTable table;
    	AddEditSheetDialog dialog;
    	
    	public AddEditSelectionListener(JTable table, AddEditSheetDialog dialog) {
    	    this.table = table;
    	    this.dialog = dialog;
    	}
    	
    	public void valueChanged(ListSelectionEvent e) {
    		dialog.refreshWordsButtons();

            if (e.getSource() == table.getColumnModel().getSelectionModel()) {
                int columnIndex = table.getSelectedColumn();
        		if(columnIndex == 2) {
        			dialog.getInputContext().selectInputMethod(
        					new Locale("ru","RU"));
        		} else {
        			dialog.getInputContext().selectInputMethod(Locale.US);
        		}
            }
    	}
    }
    
    
    /**
     * EditSheetCellEditor is a custom cell editor for words table in 
     * AddEditSheetDialog
     * @author Konstantin Fadeyev
     *
     */
    private class EditSheetCellEditor extends AbstractCellEditor 
    									implements TableCellEditor {
        private int currentColumn;
        private boolean movedWithRightArrow;
        private JTextField promptTextField;
        private JTable table;
        private JTextField transcriptionTextField;
        private JTextField translationTextField;
        private JTextField wordTextField;
        
        
        public EditSheetCellEditor(JTable _table) {
        	wordTextField = TableTextFieldFactory.createTableTextField();
        	LimitedPlainDocument wordDocument = 
        		new LimitedPlainDocument(Settings.WORD_MAX_LENGTH);
        	wordTextField.setDocument(wordDocument);
        	
        	translationTextField = TableTextFieldFactory.createTableTextField();
        	LimitedPlainDocument translationDocument = 
        		new LimitedPlainDocument(Settings.TRANSLATION_MAX_LENGTH);
        	translationTextField.setDocument(translationDocument);
        	
        	promptTextField = TableTextFieldFactory.createTableTextField();
        	LimitedPlainDocument promptDocument = 
        		new LimitedPlainDocument(Settings.PROMPT_MAX_LENGTH);
        	promptTextField.setDocument(promptDocument);
        	
        	transcriptionTextField = TableTextFieldFactory.createTableTextField(
        			new TransTextField());  	
        	LimitedPlainDocument transcriptionDocument = 
        		new LimitedPlainDocument(Settings.TRANSCRIPTION_MAX_LENGTH);
        	transcriptionTextField.setDocument(transcriptionDocument);
        	currentColumn = 0; 
        	this.table = _table;
        	movedWithRightArrow = false;

        	wordTextField.addKeyListener(
                	new TableFieldKeyListener(wordTextField));
        	translationTextField.addKeyListener(
                	new TableFieldKeyListener(translationTextField));
        	promptTextField.addKeyListener(
                	new TableFieldKeyListener(promptTextField));
        	transcriptionTextField.addKeyListener(
        			new TableFieldKeyListener(transcriptionTextField));
        }
        
        
        public Object getCellEditorValue() {
        	switch(currentColumn) {
        	case 0:
        		return wordTextField.getText();
        	case 1:
        		return transcriptionTextField.getText();
        	case 2:
        		return translationTextField.getText();
        	default:
        		return promptTextField.getText();
        	}
        }
        
        
        public Component getTableCellEditorComponent(JTable table,Object value,
        						boolean isSelected, int row, int column) {
        	currentColumn = column;
        	switch(column) {
        	case 0:
        		wordTextField.setText((String)value);
        		return wordTextField;
        	case 1:
        		transcriptionTextField.setText((String)value);
        		if(movedWithRightArrow) {
        			movedWithRightArrow = false;
        			transcriptionTextField.setCaretPosition(0);
        		}
        		return transcriptionTextField;
        	case 2:
        		translationTextField.setText((String)value);
        		if(movedWithRightArrow) {
        			movedWithRightArrow = false;
        			translationTextField.setCaretPosition(0);
        		}
        		return translationTextField;
        	default:
        		promptTextField.setText((String)value);
	    		if(movedWithRightArrow) {
	    			movedWithRightArrow = false;
	    			promptTextField.setCaretPosition(0);
	    		}
	    		return promptTextField;       		
        	}
        }
        
        
        private class TableFieldKeyListener extends KeyAdapter {
        	private JTextField textField;
        	
        	public TableFieldKeyListener(JTextField textField) {
        		this.textField = textField;
        	}
        	
    		public void keyPressed(KeyEvent e) {
    			if(e.getKeyCode() == KeyEvent.VK_LEFT) {
    				int index = textField.getCaretPosition();
    				if(index == 0) {
    					int column = table.getEditingColumn();
    					int row = table.getEditingRow();
    					if(column > 0) {  
    						stopCellEditing();
    						table.setColumnSelectionInterval(column-1, column-1);
    						table.setRowSelectionInterval(row, row);
    					}
    				}
    			}
    			if(e.getKeyCode() == KeyEvent.VK_RIGHT) {
    				int index = textField.getCaretPosition();
    				if(index == textField.getText().length()) {
    					int column = table.getEditingColumn();
    					int row = table.getEditingRow();
    					if(column < table.getModel().getColumnCount()-1) {  
    						stopCellEditing();
    						table.setColumnSelectionInterval(column+1, column+1);
    						table.setRowSelectionInterval(row, row);
    						movedWithRightArrow = true;
    					}
    				}
    			}
    		}
        }
    }
    
    
    /**
     * EditSheetTableCellRenderer class represents cell renderer
     * for words table in AddEditSheetDialog
     * @author Konstantin Fadeyev
     *
     */
    private class EditSheetTableCellRenderer extends DefaultTableCellRenderer {
        private Font defaultFont; 
        private Font transcriptionFont; 
        
        
        public EditSheetTableCellRenderer() {
        	defaultFont = (new JTextField()).getFont();
        	transcriptionFont = new Font("LucidaSans", 
        			defaultFont.getStyle(), defaultFont.getSize());
        }

        public Component getTableCellRendererComponent(JTable table, 
        		Object value, boolean isSelected, boolean hasFocus, 
        		int row, int column) {
            Component cell = super.getTableCellRendererComponent(table, value, 
            		isSelected, hasFocus, row, column);
            cell.setForeground(Color.black);
            if(isSelected)
                cell.setBackground(SELECTION_COLOR);
            else
                cell.setBackground(Color.white);
            if(hasFocus)
                cell.setBackground(Color.white);
            if(column == 1) {
            	cell.setFont(transcriptionFont);
            } else {
            	cell.setFont(defaultFont);
            }
            if(hasFocus && isSelected) {
                TableModel tblModel = table.getModel();
                if(tblModel.isCellEditable(row, column)) {
                    table.editCellAt(row, column);
                    table.getEditorComponent().requestFocus();
                }
            }
            return cell;
        }
    }


    /**
     * EditSheetTableModel class represents table model
     * for words table in AddEditSheetDialog
     * @author Konstantin Fadeyev
     *
     */
    private class EditSheetTableModel extends AbstractTableModel {
    	private WordEditList editList;

    	public EditSheetTableModel(WordEditList editList)	{
    		super();
    		this.editList = editList;
    	}

    	public Class<?> getColumnClass(int c) {
            return getValueAt(0, c).getClass();
        }

    	public int getColumnCount() {
    		return 4;
    	}

    	public String getColumnName(int num) {
    		switch(num) {
    		case 0:
    			return "Word";
    		case 1:
    			return "Transcription";
    		case 2:
    			return "Translation";
            default:
                return "Prompt";
    		}
    	}

        public int getRowCount() {
             return editList.nonDeleteSize() + 1;
    	}

    	public Object getValueAt(int row, int column) {
    		switch(column) {
    		case 0:
    			if(row < editList.nonDeleteSize()) {
    				WordEditListRecord record = editList.getNonDeleteRecord(row);
    				return record.getWordRecord().getWord();
    			} else {
    				return "";
    			}
    		case 1:
    			if(row < editList.nonDeleteSize()) {
    				WordEditListRecord record = editList.getNonDeleteRecord(row);
    				return record.getWordRecord().getTranscription();
    			} else {
    				return "";
    			}
    		case 2:
    			if(row < editList.nonDeleteSize()) {
    				WordEditListRecord record = editList.getNonDeleteRecord(row);
    				return record.getWordRecord().getTranslation();
    			} else {
    				return "";
    			}
           default:
                if(row < editList.nonDeleteSize()) {
                	WordEditListRecord record = editList.getNonDeleteRecord(row);
    				return record.getWordRecord().getPrompt();
    			} else {
    				return "";
    			}
    		}
    	}

    	public boolean isCellEditable(int rowIndex, int columnIndex) {  	
    		if(rowIndex <= editList.nonDeleteSize())
                return true;
            else
                return false;
        }

        public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
            switch(columnIndex)	{
    		case 0:
    			if(rowIndex < editList.nonDeleteSize()) {
    				WordEditListRecord record = editList.getNonDeleteRecord(
    						rowIndex);
    				record.getWordRecord().setWord(((String)aValue).trim());
            		if (record.status == WordEditListRecord.NO_CHANGE) {
            			record.status = WordEditListRecord.UPDATED;
            		}
                } else if(rowIndex == editList.nonDeleteSize()) {
                	if(!((String)aValue).equals("")) {
                		editList.addRecord(((String)aValue).trim(),"","","");
                	}
                }
                break;
    		case 1:
    			if(rowIndex < editList.nonDeleteSize()) {
    				WordEditListRecord record = editList.getNonDeleteRecord(
    						rowIndex);
    				record.getWordRecord().setTranscription(((String)aValue).trim());
    				if (record.status == WordEditListRecord.NO_CHANGE) {
            			record.status = WordEditListRecord.UPDATED;
            		}
                } else if(rowIndex == editList.nonDeleteSize()) {
                	if(!((String)aValue).equals("")) {
                		editList.addRecord("",((String)aValue).trim(),"",""); 
                	}
                }
                break;
    		case 2:
    			if(rowIndex < editList.nonDeleteSize()) {
    				WordEditListRecord record = editList.getNonDeleteRecord(
    						rowIndex);
    				record.getWordRecord().setTranslation(((String)aValue).trim());
    				if (record.status == WordEditListRecord.NO_CHANGE) {
            			record.status = WordEditListRecord.UPDATED;
            		}
    			} else if(rowIndex == editList.nonDeleteSize()) {
                	if(!((String)aValue).equals("")) {
                		editList.addRecord("","",((String)aValue).trim(),"");
                	}
                }
                break;
    		default:
    			if(rowIndex < editList.nonDeleteSize()) {
    				WordEditListRecord record = editList.getNonDeleteRecord(
    						rowIndex);
    				record.getWordRecord().setPrompt(((String)aValue).trim());
    				if (record.status == WordEditListRecord.NO_CHANGE) {
            			record.status = WordEditListRecord.UPDATED;
            		}
                } else if(rowIndex == editList.nonDeleteSize()) {
                	if(!((String)aValue).equals("")) {
                		editList.addRecord("","","",((String)aValue).trim());
                	}
                }
                break;
    		}
            fireTableDataChanged();
    	}
    }   
}
